package com.suray.wcs.service.pojo.rgv.rgv.protocol.message;

import com.suray.basic.wcs.path.core.Node;
import com.suray.basic.wcs.path.enums.DirectionStatus;
import com.suray.basic.wcs.utils.LoggerUtil;
import com.suray.commin.core.utils.SpringContextHolder;
import com.suray.wcs.res.enums.PalletStatus;
import com.suray.wcs.res.enums.RgvStatus;
import com.suray.wcs.service.core.util.LockNodeManager;
import com.suray.wcs.service.enums.ElectricStatus;
import com.suray.wcs.service.init.SystemInit;
import com.suray.wcs.service.pojo.Rgv;
import com.suray.basic.wcs.utils.typedef.Bit;
import com.suray.basic.wcs.utils.typedef.Byte;
import com.suray.basic.wcs.utils.typedef.DWord;
import com.suray.basic.wcs.utils.typedef.Word;
import com.suray.wcs.service.pojo.rgv.action.util.RgvActionStatus;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.base.RgvRecMessage;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.util.RgvCargoStatus;
import com.suray.wcs.service.pojo.rgv.rgv.protocol.util.RgvMessageType;
import com.suray.wcs.service.rescontact.ResultContainer;
import com.suray.wcs.service.system.service.impl.CodeDBServiceImpl;
import com.suray.wcs.service.system.service.impl.RgvDBServiceImpl;
import com.suray.wcs.service.system.service.impl.WareHouseDBServiceImpl;

import java.io.IOException;
import java.util.Arrays;

public class RgvLifeRecMessage extends RgvRecMessage {

    private RgvDBServiceImpl rgvDBService = SpringContextHolder.getBean(RgvDBServiceImpl.class);
    private static final CodeDBServiceImpl codeDBService = SpringContextHolder.getBean(CodeDBServiceImpl.class);

    public RgvLifeRecMessage(Rgv rgv) {
        super(rgv, "心跳接收");

        baseDatas.add(new Word("头帧", "取值0x02FD"));
        baseDatas.add(new Byte("设备ID", "取值范围：0-255， 小车对应设备号"));
        baseDatas.add(new Byte("life", "0-255"));
        baseDatas.add(new Bit(2, "时间是否同步", "0:不同步，1同步"));
        baseDatas.add(new Bit(2, "序号类型", "1.cmdNo为任务，2.cmdNo为指令，其他无效"));
        baseDatas.add(new Bit(4, "报文类型", "0:心跳，1：整体任务，2：指令，3：调试指令"));
        baseDatas.add(new Byte("任务/指令 编号", "1-255"));
        baseDatas.add(new Word("执行结果", "1：进行中，2.执行完成"));
        baseDatas.add(new Byte("x", "x坐标"));
        baseDatas.add(new Byte("y", "y坐标"));
        baseDatas.add(new Byte("z", "z坐标"));
        baseDatas.add(new Byte("currentSegment", "当前小车行驶所在的段序号"));
        baseDatas.add(new DWord("条码值", "表示小车当前所在位置的条码值（或海康威视扫码带偏移量，从左向右第一个字节：0/1 :0代表实时，1代表非实时  第二个字节：0x50(坡道)/ 0x58(巷道)  后两个字节：偏移值,最高位是符号位）  像素扫码器上送的就是当前的条码值"));
        baseDatas.add(new Bit(4, "托板状态", "0：托板降状态；1：托板升状态；2：异常状态；"));
        baseDatas.add(new Bit(4, "小车状态", "1：任务执行中；2：指令执行中；3：就绪；4：暂停，5：充电中；6：故障；"));
        baseDatas.add(new Bit(4, "行驶方向", "0:静止中；1：1方向；2:2方向；3:3方向；4:4方向；"));
        baseDatas.add(new Bit(4, "换向状态", "1:巷道；   2：坡道（16进制）；"));
        baseDatas.add(new Byte("状态描述", "0：无警告；   1：行驶控制板失联； 2：液压控制板失联； 3：行驶驱动器失联； 4：液压驱动器失联； 5：行驶驱动器出现异常 ；6：液压驱动器出现异常 ；7：小车充电异常；"));
        baseDatas.add(new Byte("HavePallet", "1有托盘    0无托盘"));
        baseDatas.add(new DWord("DriverWarning", "具体的错误原因"));
        baseDatas.add(new Byte("电量", "小车电量"));
        baseDatas.add(new Word("报文长度", "整条报文的长度"));
        baseDatas.add(new Word("校验位", "CRC（循环冗余校验；低位在前，高位在后），采用crc16_modbus"));
        baseDatas.add(new Word("尾帧", "0x3FC"));

    }

    public int getBattery() {
        return getValue("电量");
    }

    public boolean isTimeSync() {
        return getValue("时间是否同步") == 1;
    }

    /**
     * 1.有货,标准位置(三个光电都有信号) 2.无货（三个光电全无信号） 3.有货但未校准（有且只有一个或两个光电有信号）
     * @return
     */
    public RgvCargoStatus getHavePallet() {
        //RES+3.1_v0.0.55.bin : 是否有货上送光电信号
        int version = 0 * 10000 + 0 * 100 + 55;

        Integer value = getValue("HavePallet");
        if (getRgv().versionCheck(version)) {
            int slant = (value >> 6) & 0b11;
            int dir3 = (value >> 4) & 0b11;
            int dir1 = (value >> 2) & 0b11;
            int haveCargo = value & 0b11;

            LoggerUtil.info("托盘倾斜校准光电：" + (slant == 0) + ", 3方向托盘校准光电:" + (dir3 == 0)
                    + ", 1方向托盘校准光电:" + (dir1 == 0) + ", 托盘检测:" + haveCargo, this.getClass());

            RgvCargoStatus result;
            if (slant == 0 && dir3 == 0 && dir1 == 0) {
                result = RgvCargoStatus.CARGO_STANDARD;
            } else if (slant == 1 && dir3 == 1 && dir1 == 1) {
                result = RgvCargoStatus.NO_CARGO;
            } else {
                result = RgvCargoStatus.CARGO_STANDARD;
            }
            return result;
        } else {
            return RgvCargoStatus.parseValue(value);
        }
    }

    public int getDriverWarning() {
        return getValue("DriverWarning");
    }

    public int getReserveStatus() {
        return getValue("换向状态");
    }

    public int getCurrentSegment() {
        return getValue("currentSegment");
    }

    public int getDriveDirection() {
        return getValue("行驶方向");
    }

    public int getDeviceNo() {
        return getValue("设备ID");
    }

    public int getCmdType() {
        return getValue("序号类型");
    }

    public int getCmdNo() {
        return getValue("任务/指令 编号");
    }

    public int getResult() {
        return getValue("执行结果");
    }

    public int getX() {
        return getValue("x");
    }

    public int getY() {
        return getValue("y");
    }

    public int getZ() {
        return getValue("z");
    }

    public int getPalletStatus() {
        return getValue("托板状态");
    }

    public int getStatusDescription() {
        return getValue("状态描述");
    }

    public int getRgvStatus() {
        return getValue("小车状态");
    }

    public int getCurBarcode() {
        return getValue("条码值");
    }

    private static Integer parseDirection(Integer resDirection, Integer carDirection) {
        if (resDirection == 0) {
            return resDirection;
        }
        if (resDirection < 0 || resDirection > 4) {
            return 5;
        }
        switch (carDirection) {
            case 3:
                return (resDirection + 0) % 4;
            case 2:
                return (resDirection + 1) % 4;
            case 1:
                return (resDirection + 2) % 4;
            case 4:
                return (resDirection + 3) % 4;
        }
        return 5;
    }

    public int getMessageLength() {
        return getValue("报文长度");
    }

    @Override
    public boolean checkMessage(byte[] recData, RgvMessageType rgvMessageType, Integer sendLife) throws IOException {
        boolean result = super.checkMessage(recData, rgvMessageType, sendLife);

        int messageLength = getMessageLength();
        if (recData.length != messageLength) {
            throw new RuntimeException("解析的报文长度与接收的实际长度不一致:" + Arrays.toString(recData));
        }

        if (result) {
            analyzeMessage();
        }

        return result;
    }

    private void analyzeMessage() {
        Rgv rgv = getRgv();

        setMessgeTime(System.currentTimeMillis());

        if (RgvStatus.parseStatus(getValue("小车状态")) != RgvStatus.OFF_LINE) {
            rgv.setPalletStatus(PalletStatus.parseStatus(getPalletStatus()));
            rgv.setDirection(parseDirection(getDriveDirection(), SystemInit.wareHouseDB == null ? 1 : SystemInit.wareHouseDB.getMapDirection()));
            rgv.setBattery(getBattery());
            if (rgv.getBattery() != null) {
                rgv.setElectricStatus(ElectricStatus.parseStatus(rgv.getBattery(), rgv));
            }
            rgv.setHasPallet(getHavePallet());
            rgv.setCurrSegment(getCurrentSegment());
            rgv.getCmdAction().setCmdParam(getCurrentSegment());

            int statusDes = getStatusDescription();
            int driverWarn = getDriverWarning();

            if (driverWarn != 0) {
                rgv.setStatusDescription(codeDBService.getCodeDescByWarning(statusDes) + "(" + driverWarn + ")");
            } else if (rgv.getCurResTaskNo() == null) {
                rgv.setStatusDescription(null);
            }
            if (driverWarn != 0) {
                rgv.setHasDriverError(true);
            } else {
                rgv.setHasDriverError(false);
            }

            if (getCurBarcode() != 0xffff1f) {
                rgv.setGroundCode(String.format("%06d", getCurBarcode()));
            } else {
                rgv.setGroundCode(null);
            }
            rgv.setDirectionStatus(DirectionStatus.parseStatus(getReserveStatus()));
            //与RES约定当坐标为(255,255,31)时视为无坐标
            if (getX() == 255 || getY() == 255 || getZ() == 31) {
                rgv.setCurLocation(null);
            } else {
                rgv.setCurLocation(new Node(getX(), getY(), getZ()));
                if (rgv.getRgvDB().getLocationNode() == null || !rgv.getRgvDB().getLocationNode().equals(rgv.getCurLocation())) {
                    rgv.getRgvDB().setLocation(rgv.getCurLocation().toString());
                    rgvDBService.updateRgvLocation(rgv.getRgvDB());
                    try {
                        LockNodeManager.updateLocationLock(rgv);
                    } catch (IllegalArgumentException e) {
//                        rgv.setRgvStatus(RgvStatus.ERROR);
//                        rgv.setErrorMessage(e.getMessage());
                    }
                }
            }
            rgv.updateWcsTimeModuleResultBO(rgv.getCurLocation());
        }
        rgv.setRgvResStatus(RgvStatus.parseStatus(getRgvStatus()));
        //心跳结果中的状态不可消除WCS中的故障状态，必须人工消除
        if (!rgv.isStopHeart()) {
            if (rgv.getRgvStatus() != RgvStatus.ERROR
                    && (rgv.getRgvStatus().getRgvStatus() <= 0xFF00 || rgv.getRgvStatus() == RgvStatus.UNKNOWN)) {
                rgv.setRgvStatus(RgvStatus.parseStatus(getRgvStatus()));
            }
        }

        int result = getResult();
        if (result == 2) {
            int cmdNo = getCmdNo();
            int type = getCmdType();
            if (type == 1) {
                if (rgv.getTaskAction().getActionNo() == cmdNo) {
                    LoggerUtil.info("任务完成：" + cmdNo, this.getClass());
                    rgv.getTaskAction().setActionStatus(RgvActionStatus.RGV_END_ACTION);
                }
            } else if (type == 2) {
                if (rgv.getCmdAction().getActionNo() == cmdNo) {
                    LoggerUtil.info("指令完成：" + cmdNo, this.getClass());
                    rgv.getCmdAction().setActionStatus(RgvActionStatus.RGV_END_ACTION);
                }
            } else if (type != 0) {
                LoggerUtil.warn("心跳报文返回‘任务/指令类型’错误:" + type, this.getClass());
            }
        } else if (result > 2) {
            rgv.getCmdAction().setActionStatus(RgvActionStatus.RGV_END_ACTION);
        }

        ResultContainer.getContainer(rgv).putReceiveMessage(getCmdNo(), this);
    }

    @Override
    public Integer getMessageLife() {
        return getValue("life");
    }

    @Override
    public Integer getMessageType() {
        return getValue("报文类型");
    }

}
